﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using UnityEditor;
using UnityEngine;

public class ExcelToolWindow : EditorWindow
{
    [MenuItem("Tools/兔子舒的工具/配置表解析器")]
    private static void ShowWindow()
    {
        GetWindow<ExcelToolWindow>("配置表解析器").Show(true);
    }


    /// <summary>
    /// 在脚本的Inspector面板拖动赋值
    /// </summary>
    public ExcelToolAsset config;

    private GUIStyle m_HintTextStyle;


    private void OnEnable()
    {
        m_HintTextStyle = new GUIStyle { fontSize = 25, alignment = TextAnchor.MiddleCenter };
        m_HintTextStyle.normal.textColor = Color.gray;
        if (config == null)
        {
            EditorUtility.DisplayDialog("配置错误", "ParserConfig文件未赋值", "确认");
            Close();
        }
    }

    private void OnGUI()
    {
        if (EditorApplication.isCompiling)
        {
            GUI.Label(new Rect(0, 0, position.width, position.height), "等待编译...", m_HintTextStyle);
            return;
        }

        // Excel临时路径
        GUILayout.Space(5);
        GUILayout.BeginHorizontal();
        GUILayout.Label("Excel临时路径", GUILayout.Width(200));
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUI.enabled = false;
        EditorGUILayout.TextField(config.excelTempPath);
        GUI.enabled = true;
        if (GUILayout.Button("...", GUILayout.Width(20)))
        {
            var path = EditorUtility.OpenFolderPanel("选择存放Excel临时文件的路径", string.IsNullOrEmpty(config.excelTempPath) ? Application.dataPath : config.excelTempPath, string.Empty);
            if (!string.IsNullOrEmpty(path))
            {
                config.excelTempPath = FileUtil.GetProjectRelativePath(path);
                EditorUtility.SetDirty(config);
            }
        }
        if (GUILayout.Button("打开文件夹", GUILayout.Width(80)))
        {
            CheckDirectory(config.excelTempPath);
            System.Diagnostics.Process.Start(Path.GetFullPath(config.excelTempPath));
        }
        GUILayout.EndHorizontal();

        // Excel保存路径
        GUILayout.Space(5);
        GUILayout.BeginHorizontal();
        GUILayout.Label("Excel保存路径", GUILayout.Width(200));
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUI.enabled = false;
        EditorGUILayout.TextField(config.excelPath);
        GUI.enabled = true;
        if (GUILayout.Button("...", GUILayout.Width(20)))
        {
            var path = EditorUtility.OpenFolderPanel("选择存放Excel配置表的路径", string.IsNullOrEmpty(config.excelPath) ? Application.dataPath : config.excelPath, string.Empty);
            if (!string.IsNullOrEmpty(path))
            {
                config.excelPath = FileUtil.GetProjectRelativePath(path);
                EditorUtility.SetDirty(config);
            }
        }
        if (GUILayout.Button("打开文件夹", GUILayout.Width(80)))
        {
            CheckDirectory(config.excelPath);
            System.Diagnostics.Process.Start(Path.GetFullPath(config.excelPath));
        }
        GUILayout.EndHorizontal();

        // Json保存路径
        GUILayout.Space(5);
        GUILayout.BeginHorizontal();
        GUILayout.Label("Json保存路径", GUILayout.Width(200));
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUI.enabled = false;
        EditorGUILayout.TextField(config.jsonPath);
        GUI.enabled = true;
        if (GUILayout.Button("...", GUILayout.Width(20)))
        {
            var path = EditorUtility.OpenFolderPanel("选择存放Json文件的路径", string.IsNullOrEmpty(config.jsonPath) ? Application.dataPath : config.jsonPath, string.Empty);
            if (!string.IsNullOrEmpty(path))
            {
                config.jsonPath = FileUtil.GetProjectRelativePath(path);
                EditorUtility.SetDirty(config);
            }
        }
        if (GUILayout.Button("打开文件夹", GUILayout.Width(80)))
        {
            CheckDirectory(config.jsonPath);
            System.Diagnostics.Process.Start(Path.GetFullPath(config.jsonPath));
        }
        GUILayout.EndHorizontal();

        // 是否格式化整理Json文件
        GUILayout.Space(5);
        EditorGUI.BeginChangeCheck();
        GUILayout.BeginHorizontal();
        config.format = GUILayout.Toggle(config.format, "Json格式化整理", GUILayout.Width(200));
        GUILayout.EndHorizontal();
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(config);
        }

        // 生成按钮
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("生成选中的Excel", GUILayout.Width(120)))
        {
            GenerateExcel(false);
        }
        if (GUILayout.Button("生成所有Excel", GUILayout.Width(120)))
        {
            GenerateExcel(true);
        }
        GUILayout.Space(10);
        if (GUILayout.Button("生成选中的Json", GUILayout.Width(120)))
        {
            GenerateJson(false);
        }
        if (GUILayout.Button("生成所有Json", GUILayout.Width(120)))
        {
            GenerateJson(true);
        }
        GUILayout.EndHorizontal();

        // 其他
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("移动所有临时Excel到正确目录", GUILayout.Width(243)))
        {
            MoveExcelToActualPath();
        }
        GUILayout.Space(10);
        if (GUILayout.Button("查看工具配置", GUILayout.Width(243)))
        {
            if (config != null)
            {
                EditorGUIUtility.PingObject(config);
                Selection.activeObject = config;
            }
        }
        GUILayout.EndHorizontal();
    }

    private void GenerateExcel(bool all)
    {
        if (config == null)
        {
            EditorUtility.DisplayDialog("Excel生成失败", "未检查到工具配置表，请在ParserForm脚本处赋值ParserConfig文件", "确认");
            return;
        }
        if (string.IsNullOrEmpty(config.excelTempPath))
        {
            EditorUtility.DisplayDialog("Excel生成失败", "Excel临时路径错误，请重新设置真确路径", "确认");
            return;
        }
        CheckDirectory(config.excelTempPath);
        var configuableTypes = all ? GetAllConfiguableTypes() : GetConfiguableTypes();
        if (configuableTypes.Count <= 0)
        {
            EditorUtility.DisplayDialog("Excel生成失败", "没有指定要生成的脚本，请在工程中使用ConfigModelAttribute进行指定", "确认");
            return;
        }
        for (int i = 0; i < configuableTypes.Count; i++)
        {
            ExcelToolCore.GenerateExcelTemplate(configuableTypes[i], config.excelTempPath);
        }
        AssetDatabase.Refresh();
        if (EditorUtility.DisplayDialog("生成成功", "Excel生成成功，是否打开存放文件夹", "打开", "取消"))
        {
            System.Diagnostics.Process.Start(Path.GetFullPath(config.excelTempPath));
        }
    }

    private void GenerateJson(bool all)
    {
        if (config == null)
        {
            EditorUtility.DisplayDialog("Json生成失败", "未检查到工具配置表，请在ParserForm脚本处赋值ParserConfig文件", "确认");
            return;
        }
        if (string.IsNullOrEmpty(config.jsonPath) || string.IsNullOrEmpty(config.excelPath))
        {
            EditorUtility.DisplayDialog("Json生成失败", "Json路径错误，请重新设置真确路径", "确认");
            return;
        }
        CheckDirectory(config.excelPath);
        CheckDirectory(config.jsonPath);
        var configuableTypes = all ? GetAllConfiguableTypes() : GetConfiguableTypes();
        if (configuableTypes.Count <= 0)
        {
            EditorUtility.DisplayDialog("Json生成失败", "请选中被[Configuable]属性标记过的脚本类、或其同名文件", "确认");
            return;
        }
        var count = 0;
        for (int i = 0; i < configuableTypes.Count; i++)
        {
            var type = configuableTypes[i];
            var configuableAttr = type.GetCustomAttribute<ConfiguableAttribute>();
            var fileName = string.IsNullOrEmpty(configuableAttr.fileName) ? type.Name : configuableAttr.fileName;
            if (ExcelToolCore.GenerateJsonFile(type, $"{config.excelPath}/{fileName}.xlsx", $"{config.jsonPath}/{fileName}.json", config.format))
            {
                count += 1;
            }
            EditorUtility.DisplayProgressBar("Client Json Generating...", fileName, i / (float)configuableTypes.Count);
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();
        EditorUtility.DisplayDialog("生成成功", $"{count}个Json配置文件生成成功", "确认");
    }

    private List<Type> GetConfiguableTypes()
    {
        var configableTypes = new List<Type>();
        var selectedObjects = Selection.objects;
        foreach (var obj in selectedObjects)
        {
            if (obj is MonoScript && (obj as MonoScript).GetClass().GetCustomAttribute<ConfiguableAttribute>() != null)
            {
                configableTypes.Add((obj as MonoScript).GetClass());
                continue;
            }

            UnityEngine.Object script = null;
            var assetPaths = AssetDatabase.FindAssets($"t:script {obj.name}");
            foreach (var assetPath in assetPaths)
            {
                script = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(assetPath), typeof(object));
                if (script.name == obj.name) break;
                script = null;
            }
            if (script != null)
            {
                configableTypes.Add((script as MonoScript).GetClass());
                continue;
            }
        }
        return configableTypes;
    }

    private List<Type> GetAllConfiguableTypes()
    {
        var configableTypes = new List<Type>();
        var assmblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assmbly in assmblies)
        {
            var types = assmbly.GetTypes();
            foreach (var type in types)
            {
                var attr = type.GetCustomAttribute<ConfiguableAttribute>();
                if (attr != null)
                {
                    configableTypes.Add(type);
                }
            }
        }
        return configableTypes;
    }

    private void CheckDirectory(string path)
    {
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
    }

    /// <summary>
    /// 移动临时Excel到正确路径
    /// </summary>
    private void MoveExcelToActualPath()
    {
        CheckDirectory(config.excelTempPath);
        CheckDirectory(config.excelPath);
        List<string> files = new List<string>(Directory.GetFiles(config.excelTempPath));
        var count = 0;
        for (int i = 0; i < files.Count; i++)
        {
            var file = files[i];
            string fileName = Path.Combine(config.excelPath, Path.GetFileName(file));
            if (!fileName.EndsWith(".xlsx")) continue;
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }
            File.Move(file, fileName);
            count++;
        }
        AssetDatabase.Refresh();
        EditorUtility.DisplayDialog("移动成功", $"{count}个Excel配置文件移动成功", "确认");
    }
}